// 经典发布订阅模式：vue2 EventBus, 浏览器自带的Event（addEventListener）

type Callback = (...args: any[]) => void;
interface IEmitter {
  on(event: string, listener: Callback): void;
  off(event: string, listener: Callback): void;
  once(event: string, listener: Callback): void;
  emit(event: string, ...args: any[]): void;
}

class Emitter implements IEmitter {
  private events: Map<string, Callback[]> = new Map() 
  once(event: string, listener: Callback): void {
    const fn = (...args: any[]) => {
      listener(...args)
      this.off(event, fn)
    }
    this.on(event, fn)
  }
  on(event: string, listener: Callback): void {
    if (this.events.has(event)) {
      const listeners = this.events.get(event)
      listeners!.push(listener)
    } else {
      this.events.set(event, [listener])
    }
  }
  off(event: string, listener: Callback): void {
    const listeners = this.events.get(event)
    if (listeners?.length) {
      listeners.splice(listeners.indexOf(listener), 1)
    }
  }
  emit(event: string, ...args: any[]): void {
    const listeners = this.events.get(event)
    if (listeners?.length) {
      listeners.forEach((fn) => fn(...args))
    }
  }
}

const emit = new Emitter()
const fn: Callback = (...args) => {
  console.log('callback执行', ...args)
}
// emit.on('aa', fn)
// emit.on('bb', fn)
// emit.on('cc', fn)

// emit.off('aa', fn)

emit.once('aa', fn)

emit.emit('aa', 1, 'lixiao')
emit.emit('aa', 1, 'lixiao')
emit.emit('aa', 1, 'lixiao')
emit.emit('aa', 1, 'lixiao')
// emit.emit('bb', 2, 'lixiao2')